package com.hilton.tigershark.downloads;

import java.net.URI;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment;
import android.text.TextUtils;
import android.util.Log;
import android.webkit.MimeTypeMap;
import android.widget.Toast;

import com.hilton.net.WebAddress;

public class DownloadHandler {
    private static final String TAG = "DownloadHandler";

    public static void onDownloadStart(Context context, String url,
            String userAgent, String contentDisposition, String mimetype, long contentLength) {
        Log.e(TAG, "donwloat start: " + url + ", ua " + userAgent + ", cd " + 
                contentDisposition + ", mime " + mimetype + " cl" + contentLength);
        // Check SD card, if not available, notify and quit
        if (sdcardNotAvailable()) {
            notifyUser(context, "no sdcard");
            return;
        }
        if (notWellFormedUrl(url)) {
            notifyUser(context, "bad URL:" + url);
            return;
        }
        
	final String filename = guessFileName(url, contentDisposition, mimetype);
	final String basepath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();
        Intent i = new Intent();
        i.setClass(context, DownloadService.class);
        final DownloadInfo info = new DownloadInfo(url, basepath, filename, userAgent, mimetype, (int) contentLength);
        i.putExtra(DownloadService.DOWNLOAD_TARGET, info);
        context.startService(i);
    }

    private static String guessFileName(String url, String contentDisposition, String mimetype) {
        String filename = "";
        if (!TextUtils.isEmpty(contentDisposition)) {
            Log.e(TAG, "con d " + contentDisposition);
            filename = parseFromContentDisposition(contentDisposition);
            Log.e(TAG, "from content dispostion " + filename);
        }
        Log.e(TAG, "after cd " + filename);
        if (TextUtils.isEmpty(filename)) {
            filename = guessFromUrl(url);
        }
        if (TextUtils.isEmpty(filename)) {
            filename = "downloadfile";
        }
        if (filename.indexOf(".") <= 0) {
            filename = fixExtension(filename, mimetype);
        }
        return filename;
    }
    
    private static String fixExtension(String filename, String mimeType) {
        String extension = null;
        if (mimeType != null) {
            extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType);
            if (extension != null) {
                extension = "." + extension;
            }
        }
        if (extension == null) {
            if (mimeType != null && mimeType.toLowerCase().startsWith("text/")) {
                if (mimeType.equalsIgnoreCase("text/html")) {
                    extension = ".html";
                } else {
                    extension = ".txt";
                }
            } else {
                extension = ".bin";
            }
        }
        return filename + extension;
    }
    private static final Pattern CONTENT_DISPOSITION_PATTERN =
            Pattern.compile("attachment;\\s*filename\\s*=\\s*(\"?)([^\"]*)\\1\\s*$",
            Pattern.CASE_INSENSITIVE);

    private static String parseFromContentDisposition(String contentDisposition) {
        String filename = "";
        try {
            Matcher m = CONTENT_DISPOSITION_PATTERN.matcher(contentDisposition);
            if (m.find()) {
                filename = m.group(2);
                Log.e(TAG, "match found " + filename);
            }
        } catch (IllegalStateException ex) {
             // This function is defined as returning null when it can't parse the header
        }
        return removePath(filename);
    }

    private static String removePath(String filename) {
        Log.e(TAG, "remove path " + filename);
        if (TextUtils.isEmpty(filename)) {
            return "";
        }
        int index = filename.lastIndexOf('/') + 1;
        if (index > 0) {
            filename = filename.substring(index);
        }
        return filename;
    }
    
    private static String guessFromUrl(String url) {
        String filename = "";
        String decodedUrl = Uri.decode(url);
        if (decodedUrl != null) {
            int queryIndex = decodedUrl.indexOf('?');
            // If there is a query string strip it, same as desktop browsers
            if (queryIndex > 0) {
                decodedUrl = decodedUrl.substring(0, queryIndex);
            }
            if (!decodedUrl.endsWith("/")) {
                filename = removePath(decodedUrl);
            }
        }
        return filename;
    }

    private static boolean notWellFormedUrl(String url) {
        // java.net.URI is a lot stricter than KURL so we have to encode some
        // extra characters. Fix for b 2538060 and b 1634719
        WebAddress webAddress;
        try {
            webAddress = new WebAddress(url);
            webAddress.mPath = encodePath(webAddress.mPath);
            final URI u = new URI(url);
        } catch (Exception e) {
            // This only happens for very bad URLs, we want to catch the
            // exception here
            Log.e(TAG, "Exception trying to parse url:" + url);
            return true;
        }
        return false;
    }
    
    // This is to work around the fact that java.net.URI throws Exceptions
    // instead of just encoding URL's properly
    // Helper method for onDownloadStartNoStream
    private static String encodePath(String path) {
        char[] chars = path.toCharArray();
        
        boolean needed = false;
        for (char c : chars) {
            if (c == '[' || c == ']') {
                needed = true;
                break;
            }
        }
        if (needed == false) {
            return path;
        }
        
        StringBuilder sb = new StringBuilder("");
        for (char c : chars) {
            if (c == '[' || c == ']') {
                sb.append('%');
                sb.append(Integer.toHexString(c));
            } else {
                sb.append(c);
            }
        }
        
        return sb.toString();
    }

    private static void notifyUser(Context ctx, String reason) {
        Toast.makeText(ctx, "Download failed: " + reason, Toast.LENGTH_SHORT).show();
    }

    private static boolean sdcardNotAvailable() {
        final String state = Environment.getExternalStorageState();
        return !state.equals(Environment.MEDIA_MOUNTED);
    }
}